package cim144.ctdp_array16_shift8_relu
import Chisel._
import chisel3.{Mux, RegInit, SInt, Vec, VecInit, when}
import chisel3.util.{Cat, log2Ceil}

object pushbuffer_shift{
  def apply(custom_push:Bool,custom_mvm:Bool,custom_save:Bool,ismvm:Bool,ispush:Bool,push_enable:Bool,push_index:UInt,
            cim_done:Bool,mem_valid:Bool,mem_data:Bits,bit_random:Bool,wise_num:UInt,
            r1:Bits,r2:Bits
           ):(Bool,UInt,Bool)={
    val inst = Module(new pushbuffer_shift()).io
    inst.custom_push:= custom_push
    inst.custom_mvm := custom_mvm
    inst.custom_save:= custom_save
    inst.ismvm      := ismvm
    inst.ispush     := ispush
    inst.push_enable:= push_enable
    inst.push_index := push_index
    inst.cim_done   := cim_done
    inst.mem_valid  := mem_valid
    inst.mem_data   := mem_data
    inst.bit_random := bit_random
    inst.wise_num   := wise_num
    inst.r1         := r1
    inst.r2         := r2
    (inst.done_tmp,inst.push_576,inst.bitwise_end)
  }
}

class pushbuffer_shift extends Module with SystemConfig{
  val io = new Bundle {
    val custom_push = Input(Bool())
    val custom_mvm  = Input(Bool())
    val custom_save = Input(Bool())
    val ismvm       = Input(Bool())
    val ispush      = Input(Bool())
    val push_enable = Input(Bool())
    val push_index  = Input(UInt(log2Ceil(PUSH_MAX_SIZE+1).W))
    val cim_done    = Input(Bool())
    val mem_valid   = Input(Bool())
    val mem_data    = Bits(INPUT,64)
    val bit_random  = Input(Bool())
    val wise_num    = Input(UInt(9.W))
    val r1          = Bits(INPUT,64)
    val r2          = Bits(INPUT,64)

    val done_tmp    = Output(Bool())
    val bitwise_end = Output(Bool())
    val push_576   = Output(UInt(ROW_NUM.W))
  }
  // rs2: *********|21********11|10********0|
  //      *********|start_index*|*push_num**|
  //      start_index and push_num should be Multiples of 8
  // rs1: |63****************memory addr***0|
  val buf_end_index       = RegInit(0.U(log2Ceil(PUSH_MAX_SIZE+1).W))
  when(io.custom_push|io.custom_save){
    buf_end_index       := io.r2(21,14)  +  io.r2(10,3) -1.U
  }
  io.done_tmp := (io.push_index === buf_end_index)
  //************************** 1.mem to push_buf
  val push_buf   = RegInit(VecInit(Seq.fill(PUSH_MAX_SIZE)(0.U(CIM_XLEN.W))))  //72 x 64 bit
  when(io.push_enable){
    push_buf(io.push_index)   := io.mem_data
  }
  //************************** 2.push_buf to push1152
    // only for positive input
  val push_buf_8bit       = push_buf.asTypeOf(Vec(ROW_NUM,UInt(8.W)))
  val push_buf_8bit_shift = VecInit(Seq.fill(ROW_NUM)(0.U(8.W)))
  val push_buf_next       = push_buf_8bit_shift.asTypeOf(Vec(PUSH_MAX_SIZE,UInt(CIM_XLEN.W)))
  val counter_wise = RegInit(0.U(4.W))
  val push_buf_sel = VecInit(Seq.fill(ROW_NUM)(0.U(1.W)))

  for(i<-0 until ROW_NUM){
    push_buf_sel(i):= push_buf_8bit(i)(0)
    push_buf_8bit_shift(i) := Cat(0.U, push_buf_8bit(i)(7,1))
    when(io.custom_mvm){
      counter_wise := 0.U
    }.elsewhen(io.cim_done){
      counter_wise := counter_wise + 1.U
      if(i < PUSH_MAX_SIZE){
        push_buf(i)  := push_buf_next(i)
      }
    }
  }
  io.push_576 := push_buf_sel.asUInt()
  io.bitwise_end := (counter_wise=== io.wise_num | counter_wise === 8.U) & io.ismvm
}


//object pushbuffer{
//  def apply(custom_push:Bool,custom_mvm:Bool,custom_save:Bool,ismvm:Bool,ispush:Bool,push_enable:Bool,push_index:UInt,
//            cim_done:Bool,mem_valid:Bool,mem_data:Bits,bit_random:Bool,wise_num:UInt,
//            r1:Bits,r2:Bits
//           ):(Bool,UInt,Bool)={
//    val inst = Module(new pushbuffer()).io
//    inst.custom_push:= custom_push
//    inst.custom_mvm := custom_mvm
//    inst.custom_save:= custom_save
//    inst.ismvm      := ismvm
//    inst.ispush     := ispush
//    inst.push_enable:= push_enable
//    inst.push_index := push_index
//    inst.cim_done   := cim_done
//    inst.mem_valid  := mem_valid
//    inst.mem_data   := mem_data
//    inst.bit_random := bit_random
//    inst.wise_num   := wise_num
//    inst.r1         := r1
//    inst.r2         := r2
//    (inst.done_tmp,inst.push_1152,inst.bitwise_end)
//  }
//}
//
//class pushbuffer extends Module with SystemConfig{
//  val io = new Bundle {
//    val custom_push = Input(Bool())
//    val custom_mvm  = Input(Bool())
//    val custom_save = Input(Bool())
//    val ismvm       = Input(Bool())
//    val ispush      = Input(Bool())
//    val push_enable = Input(Bool())
//    val push_index  = Input(UInt(log2Ceil(PUSH_MAX_SIZE+1).W))
//    val cim_done    = Input(Bool())
//    val mem_valid   = Input(Bool())
//    val mem_data    = Bits(INPUT,64)
//    val bit_random  = Input(Bool())
//    val wise_num    = Input(UInt(9.W))
//    val r1          = Bits(INPUT,64)
//    val r2          = Bits(INPUT,64)
//
//    val done_tmp    = Output(Bool())
//    val bitwise_end = Output(Bool())
//    val push_1152   = Output(UInt(1152.W))
//  }
//  // rs2: *********|21********11|10********0|
//  //      *********|start_index*|*push_num**|
//  //      start_index and push_num should be Multiples of 8
//  // rs1: |63****************memory addr***0|
//  val buf_end_index       = RegInit(0.U(log2Ceil(PUSH_MAX_SIZE+1).W))
////  val push_save_buf_cnt   = RegInit(0.U(log2Ceil(PUSH_MAX_SIZE+1).W))   // 7bit
////  val baseAddr            = RegInit(0.U(CIM_XLEN.W))
//  when(io.custom_push|io.custom_save){
//    buf_end_index       := io.r2(21,14)  +  io.r2(10,3) -1.U
//    //push_save_buf_cnt   := io.r2(21,14)
//    //baseAddr            := io.r1
//  }
//  //io.done := (io.push_index === buf_end_index) & io.ispush & io.mem_valid
//  io.done_tmp := (io.push_index === buf_end_index)
//  //************************** 1.mem to push_buf
//  val push_buf   = RegInit(VecInit(Seq.fill(PUSH_MAX_SIZE)(0.U(CIM_XLEN.W))))  //72 x 64 bit
//  when(io.push_enable){
//    push_buf(io.push_index)   := io.mem_data
//  }
//  //************************** 2.push_buf to push1152
//  val push_buf_8bit = push_buf.asTypeOf(Vec(ROW_NUM,SInt(8.W)))
//  val push_buf_8bit_usign = VecInit(Seq.fill(ROW_NUM)(0.U(7.W)))
//  val counter_576 = RegInit(VecInit(Seq.fill(ROW_NUM)(0.U(7.W))))
//  val compare_576 = VecInit(Seq.fill(ROW_NUM)(false.B))
//  val push_buf_sel = VecInit(Seq.fill(ROW_NUM)(0.U(2.W)))
//
//  for(i<-0 until ROW_NUM){
//    push_buf_8bit_usign(i) := Mux(push_buf_8bit(i)(7),-push_buf_8bit(i),push_buf_8bit(i)).asUInt
//    compare_576(i) := push_buf_8bit_usign(i) > counter_576(i)
//    push_buf_sel(i):= Cat(compare_576(i)&push_buf_8bit(i)(7),compare_576(i)& !push_buf_8bit(i)(7))
//    when(io.custom_mvm){
//      counter_576(i) := Mux(io.bit_random,(i%128).U,0.U)
//    }.elsewhen(io.cim_done){
//      counter_576(i) := counter_576(i) + 1.U
//    }
//  }
//  io.push_1152 := push_buf_sel.asUInt()
//  io.bitwise_end := (counter_576(0)=== io.wise_num) & io.ismvm
//
//}

